﻿// No word splitting is allowed, thus all the following methods are for research IDEAS only
///////////////////////////////////////////////////////////////////////////////////////////
// ٦_١١٥	وتمت كلمت ربك صدقا وعدلا لا مبدل لكلمته وهو السميع العليم
// 6:115	And the Words of your Lord has been prefected full of Truth and Justice:
//          None can change His Words, and He is the All-hearing, All-knowing.
///////////////////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Text;

using DigitalQuran.Collection;
using DigitalQuran.Extensions;
using DigitalQuran.Numerology;
using DigitalQuran.IO;

namespace DigitalQuran.Research
{
    public static class NavigationResearch
    {
        #region Letter
        [ResearchMethod(Edition.Research)]        
        public static void JumpLettersByX(ResearchAgent agent, int step = 1)
        {
            if (agent.Client.Selection == null) return;

            char[] result = DoJumpLettersByX(agent.Client.Selection.ToString(agent.Client.ActiveTextMode), step);

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpLettersByX";
            
            agent.SaveLetters(path, result);
        }

        [ResearchMethod(Edition.Research)]
        public static void JumpLettersByValues(ResearchAgent agent)
        {            
            if (agent.Client.Selection == null) return;
            
            char[] result = DoJumpLettersByValues(agent.Client.Selection.ToString(agent.Client.ActiveTextMode));

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpLettersByValues";
            agent.SaveLetters(path, result);            
        }

        [ResearchMethod(Edition.Research)]
        public static void JumpLettersByPrimeNumbers(ResearchAgent agent)
        {            
            if (agent.Client.Selection == null) return;
            
            char[] result = DoJumpLettersByPrimeNumbers(agent.Client.Selection.ToString(agent.Client.ActiveTextMode));

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpLettersByPrimeNumbers";
            agent.SaveLetters(path, result);
        }

        [ResearchMethod(Edition.Research)]
        public static void JumpLettersByAdditivePrimeNumbers(ResearchAgent agent)
        {
            if (agent.Client.Selection == null) return;
            
            char[] result = DoJumpLettersByAdditivePrimeNumbers(agent.Client.Selection.ToString(agent.Client.ActiveTextMode));

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpLettersByAdditivePrimeNumbers";
            agent.SaveLetters(path, result);
        }

        [ResearchMethod(Edition.Research)]
        public static void JumpLettersByPurePrimeNumbers(ResearchAgent agent)
        {            
            if (agent.Client.Selection == null) return;
            
            char[] result = DoJumpLettersByPurePrimeNumbers(agent.Client.Selection.ToString(agent.Client.ActiveTextMode));

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpLettersByPurePrimeNumbers";
            agent.SaveLetters(path, result);            
        }

        [ResearchMethod(Edition.Research)]
        public static void JumpLettersByFibonacciNumbers(ResearchAgent agent)
        {
            // 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...            
            if (agent.Client.Selection == null) return;
            
            char[] result = DoJumpLettersByFibonacciNumbers(agent.Client.Selection.ToString(agent.Client.ActiveTextMode));

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpLettersByFibonacciNumbers";
            agent.SaveLetters(path, result);            
        }

        [ResearchMethod(Edition.Research)]
        public static void JumpLettersByPiDigits(ResearchAgent agent)
        {
            // 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327...            
            if (agent.Client.Selection == null) return;
            
            char[] result = DoJumpLettersByPiDigits(agent.Client.Selection.ToString(agent.Client.ActiveTextMode));

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpLettersByPiDigits";
            agent.SaveLetters(path, result);            
        }

        [ResearchMethod(Edition.Research)]
        public static void JumpLettersByEulerDigits(ResearchAgent agent)
        {
            // 2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642742746639193200305992181741359662904357290033429526059563073813232862794349076323382988075319525101901157383418793070215408914993488416750924476146066808226480016847741185374234544243710753907774499206955170276183860626133138458300075204493382656029760673711320070932870912744374704723069697720931014169283681902551510865746377211125238978442505695369677078544996996794686445490598793163688923009879312773617821542499922957635148220826989519366803318252886939849646510582093923982948879332036250944311730123819706841614039701983767932068328237646480429531180232878250981945581530175671736133206981125099618188159304169035159888851934580727386673858942287922849989208680582574927961048419844436346324496848756023362482704197862320900216099023530436994184914631409343173814364054625315209618369088870701676839642437814059271456354906130310720851038375051011574770417189861068739696552126715468895703503540212340784981933432106...            
            if (agent.Client.Selection == null) return;
            
            char[] result = DoJumpLettersByEulerDigits(agent.Client.Selection.ToString(agent.Client.ActiveTextMode));

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpLettersByEulerDigits";
            agent.SaveLetters(path, result);            
        }

        [ResearchMethod(Edition.Research)]
        public static void JumpLettersByGoldenRatioDigits(ResearchAgent agent)
        {
            // 1.61803398874989484820458683436563811772030917980576286213544862270526046281890244970720720418939113748475408807538689175212663386222353693179318006076672635443338908659593958290563832266131992829026788067520876689250171169620703222104321626954862629631361443814975870122034080588795445474924618569536486444924104432077134494704956584678850987433944221254487706647809158846074998871240076521705751797883416625624940758906970400028121042762177111777805315317141011704666599146697987317613560067087480710131795236894275219484353056783002287856997829778347845878228911097625003026961561700250464338243776486102838312683303724292675263116533924731671112115881863851331620384005222165791286675294654906811317159934323597349498509040947621322298101726107059611645629909816290555208524790352406020172799747175342777592778625619432082750513121815628551222480939471234145170223735805772786160086883829523045926478780178899219902707769038953219681986151437803149974110692608867429622675756052317277752035361393621076738937645560606059...            
            if (agent.Client.Selection == null) return;

            char[] result = DoJumpLettersByGoldenRatioDigits(agent.Client.Selection.ToString(agent.Client.ActiveTextMode));

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpLettersByGoldenRatioDigits";
            agent.SaveLetters(path, result);            
        }

        public static char[] DoJumpLettersByX(string versesText, int step)
        {
            int count = versesText.Length;
            char[] result = new char[count];
            versesText = versesText.Replace("\r", "").Replace("\n", "_");
            int newCount = versesText.Length;

            int i = 0;
            int r = 0;

            if (step > 0)
            {
                while (i < newCount)
                {
                    if (versesText[i] == '_')
                    {
                        result[r++] = '\r';
                        result[r++] = '\n';
                    }
                    else
                    {
                        result[r++] = versesText[i];
                    }
                    i += step;
                }
            }
            return result;
        }

        public static char[] DoJumpLettersByValues(string versesText)
        {
            int count = versesText.Length;
            char[] result = new char[count];
            versesText = versesText.Replace("\r", "").Replace("\n", "_");

            int newCount = versesText.Length;
            int i = 0;
            int r = 0;
            while (i < newCount)
            {
                if (versesText[i] == '_')
                {
                    result[r++] = '\r';
                    result[r++] = '\n';
                    i++; // skip '_'
                }
                else
                {
                    result[r++] = versesText[i];
                    try
                    {
                        i += (int)Client.Instance.Numerology.CalculateValue(versesText[i].ToString());
                    }
                    catch
                    {
                        // skip exceptions (in Abjad)
                        i += 1;
                    }
                }
            }
            return result;
        }

        public static char[] DoJumpLettersByPrimeNumbers(string versesText)
        {
            versesText = versesText.Replace("\r", "").Replace("\n", "_");

            int count = versesText.Length;
            char[] result = new char[count];
            int r = 0; // result index
            int l = 0; // letter index
            for (int i = 0; i < count - 1; i++) // count - 1 to ignore last newline
            {
                if ((l + 1).IsPrime())
                {
                    if (versesText[i] == '_')
                    {
                        result[r++] = '\r';
                        result[r++] = '\n';
                        i++; // skip '_'
                    }
                    result[r++] = versesText[i];
                }
                l++;
            }
            return result;
        }

        public static char[] DoJumpLettersByAdditivePrimeNumbers(string versesText)
        {
            versesText = versesText.Replace("\r", "").Replace("\n", "_");
            int count = versesText.Length;
            char[] result = new char[count];
            int r = 0; // result index
            int l = 0; // letter index
            for (int i = 0; i < count - 1; i++) // count - 1 to ignore last newline
            {
                if ((l + 1).IsAdditivePrime())
                {
                    if (versesText[i] == '_')
                    {
                        result[r++] = '\r';
                        result[r++] = '\n';
                        i++; // skip '_'
                    }
                    result[r++] = versesText[i];
                }
                l++;
            }
            return result;
        }

        public static char[] DoJumpLettersByPurePrimeNumbers(string versesText)
        {
            versesText = versesText.Replace("\r", "").Replace("\n", "_");

            int count = versesText.Length;
            char[] result = new char[count];
            int r = 0; // result index
            int l = 0; // letter index
            for (int i = 0; i < count - 1; i++) // count - 1 to ignore last newline
            {
                if ((l + 1).IsPurePrime())
                {
                    if (versesText[i] == '_')
                    {
                        result[r++] = '\r';
                        result[r++] = '\n';
                        i++; // skip '_'
                    }
                    result[r++] = versesText[i];
                }
                l++;
            }
            return result;
        }

        public static char[] DoJumpLettersByFibonacciNumbers(string versesText)
        {
            versesText = versesText.Replace("\r", "").Replace("\n", "_");

            int count = versesText.Length;
            char[] result = new char[count];
            int r = 0; // result index
            int l = 0; // letter index
            int N1 = 0;
            int N2 = 1;
            int Fn = N1 + N2;
            result[r++] = versesText[0]; // add first 1 of Fibonacci numbers (1, 1, 2, 3, 5, 8, ...)
            for (int i = 0; i < count - 1; i++) // count - 1 to ignore last newline
            {
                if (l == (Fn - 1))
                {
                    if (versesText[i] == '_')
                    {
                        result[r++] = '\r';
                        result[r++] = '\n';
                        i++; // skip '_'
                    }
                    result[r++] = versesText[i];

                    // next fibonacci number
                    N1 = N2;
                    N2 = Fn;
                    Fn = N1 + N2;
                    if (Fn >= count)
                    {
                        break;
                    }
                }
                l++;
            }
            return result;
        }

        public static char[] DoJumpLettersByPiDigits(string versesText)
        {
            versesText = versesText.Replace("\r", "").Replace("\n", "_");
            int count = versesText.Length;
            char[] result = new char[count];
            int r = 0; // result index
            int d = 0; // digit index
            for (int i = 0; i < count; ) // i++) // advance inside loop
            {
                // advance pi_digit amount ignoring white spaces
                int jCount = Numbers.PiDigits[d++];
                for (int j = 0; j < jCount; j++)
                {
                    if (i < count)
                    {
                        if (versesText[i] == '_')
                        {
                            result[r++] = '\r';
                            result[r++] = '\n';
                        }
                    }

                    // in all cases, advance to next letter
                    i++;
                }

                // add the 0th-based letter to result
                if ((i - 1) < count)
                {
                    result[r++] = versesText[i - 1];
                }
            }

            result = new String(result).ToCharArray();
            return result;
        }

        public static char[] DoJumpLettersByEulerDigits(string versesText)
        {
            versesText = versesText.Replace("\r", "").Replace("\n", "_");

            int count = versesText.Length;
            char[] result = new char[count];
            int r = 0; // result index
            int d = 0; // digit index
            for (int i = 0; i < count; ) // i++) // advance inside loop
            {
                // advance e_digit amount ignoring white spaces
                int jCount = Numbers.EDigits[d++];
                for (int j = 0; j < jCount; j++)
                {
                    if (i < count)
                    {
                        if (versesText[i] == '_')
                        {
                            result[r++] = '\r';
                            result[r++] = '\n';
                        }
                    }

                    // in all cases, advance to next letter
                    i++;
                }

                // add the 0th-based letter to result
                if ((i - 1) < count)
                {
                    result[r++] = versesText[i - 1];
                }
            }

            result = new String(result).ToCharArray();
            return result;
        }

        public static char[] DoJumpLettersByGoldenRatioDigits(string versesText)
        {
            versesText = versesText.Replace("\r", "").Replace("\n", "_");

            int count = versesText.Length;
            char[] result = new char[count];
            int r = 0; // result index
            int d = 0; // digit index
            for (int i = 0; i < count; ) // i++) // advance inside loop
            {
                // advance phi_digit amount ignoring white spaces
                int jCount = Numbers.PhiDigits[d++];
                for (int j = 0; j < jCount; j++)
                {
                    if (i < count)
                    {
                        if (versesText[i] == '_')
                        {
                            result[r++] = '\r';
                            result[r++] = '\n';
                        }
                    }

                    // in all cases, advance to next letter
                    i++;
                }

                // add the 0th-based letter to result
                if ((i - 1) < count)
                {
                    result[r++] = versesText[i - 1];
                }
            }

            result = new String(result).ToCharArray();
            return result;
        }
        #endregion

        #region Word
        [ResearchMethod()]
        public static void JumpWordsByX(ResearchAgent agent, int step = 1)
        {            
            if (agent.Client.Selection == null) return;

            List<string> result = DoJumpWordsByX(agent, Book.Instance.Verses, step);

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpWordsByX";
            agent.SaveWords(path, result);
        }

        [ResearchMethod()]
        public static void JumpWordsByPrimeNumbers(ResearchAgent agent)
        {
            if (agent.Client.Selection == null) return;

            List<string> result = DoJumpWordsByPrimeNumbers(agent, Book.Instance.Verses);

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpWordsByPrimeNumbers";
            agent.SaveWords(path, result);            
        }

        [ResearchMethod()]
        public static void JumpWordsByAdditivePrimeNumbers(ResearchAgent agent)
        {            
            if (agent.Client.Selection == null) return;

            List<string> result = DoJumpWordsByAdditivePrimeNumbers(agent, Book.Instance.Verses);

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpWordsByAdditivePrimeNumbers";
            agent.SaveWords(path, result);            
        }

        [ResearchMethod()]
        public static void JumpWordsByPurePrimeNumbers(ResearchAgent agent)
        {
            if (agent.Client.Selection == null) return;

            List<string> result = DoJumpWordsByPurePrimeNumbers(agent, Book.Instance.Verses);

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpWordsByPurePrimeNumbers";
            agent.SaveWords(path, result);            
        }

        [ResearchMethod()]
        public static void JumpWordsByFibonacciNumbers(ResearchAgent agent)
        {            
            if (agent.Client.Selection == null) return;

            List<string> result = DoJumpWordsByFibonacciNumbers(agent, Book.Instance.Verses);

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpWordsByFibonacciNumbers";
            agent.SaveWords(path, result);            
        }

        [ResearchMethod()]
        public static void JumpWordsByPiDigits(ResearchAgent agent)
        {            
            if (agent.Client.Selection == null) return;

            List<string> result = DoJumpWordsByPiDigits(agent, Book.Instance.Verses);

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpWordsByPiDigits";
            agent.SaveWords(path, result);            
        }

        [ResearchMethod()]
        public static void JumpWordsByEulerDigits(ResearchAgent agent)
        {
            if (agent.Client.Selection == null) return;

            List<string> result = DoJumpWordsByEulerDigits(agent, Book.Instance.Verses);

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpWordsByEulerDigits";
            agent.SaveWords(path, result);
        }

        [ResearchMethod()]
        public static void JumpWordsByGoldenRatioDigits(ResearchAgent agent)
        {            
            if (agent.Client.Selection == null) return;

            List<string> result = DoJumpWordsByGoldenRatioDigits(agent, Book.Instance.Verses);

            string path = agent.Client.Numerology.ActiveSystem.ToString() + "_JumpWordsByGoldenRatioDigits";
            agent.SaveWords(path, result);            
        }

        public static List<string> DoJumpWordsByX(ResearchAgent agent, VerseCollection verses, int step)
        {
            List<string> result = new List<string>();

            List<Word> words = new List<Word>();
            foreach (Verse verse in verses)
            {
                words.AddRange(verse.Words);
                words.Add(null); // to mark end of verse
            }
            words.RemoveAt(words.Count - 1);

            for (int i = 0; i < words.Count; i++)
            {
                if (words[i] == null)
                {
                    result.Add("\r\n");
                    words.RemoveAt(i);
                }

                if ((i % step) == 0)
                {
                    result.Add(words[i].ToString(agent.Client.ActiveTextMode) + " ");
                }
            }

            return result;
        }

        public static List<string> DoJumpWordsByPrimeNumbers(ResearchAgent agent, VerseCollection verses)
        {
            List<string> result = new List<string>();

            List<Word> words = new List<Word>();
            foreach (Verse verse in verses)
            {
                words.AddRange(verse.Words);
                words.Add(null); // to mark end of verse
            }

            words.RemoveAt(words.Count - 1);

            for (int i = 0; i < words.Count; i++)
            {
                if (words[i] == null)
                {
                    result.Add("\r\n");
                    words.RemoveAt(i);
                }

                if (Array.BinarySearch<long>(Numbers.Primes, i + 1) != -1)
                {
                    result.Add(words[i].ToString(agent.Client.ActiveTextMode) + " ");
                }
            }

            return result;
        }

        public static List<string> DoJumpWordsByAdditivePrimeNumbers(ResearchAgent agent, VerseCollection verses)
        {
            List<string> result = new List<string>();

            List<Word> words = new List<Word>();
            foreach (Verse verse in verses)
            {
                words.AddRange(verse.Words);
                words.Add(null); // to mark end of verse
            }

            words.RemoveAt(words.Count - 1);

            for (int i = 0; i < words.Count; i++)
            {
                if (words[i] == null)
                {
                    result.Add("\r\n");
                    words.RemoveAt(i);
                }

                if (Array.BinarySearch<long>(Numbers.AdditivePrimes, (long)i + 1) != -1)
                {
                    result.Add(words[i].ToString(agent.Client.ActiveTextMode) + " ");
                }
            }

            return result;
        }

        public static List<string> DoJumpWordsByPurePrimeNumbers(ResearchAgent agent, VerseCollection verses)
        {
            List<string> result = new List<string>();

            List<Word> words = new List<Word>();
            foreach (Verse verse in verses)
            {
                words.AddRange(verse.Words);
                words.Add(null); // to mark end of verse
            }

            words.RemoveAt(words.Count - 1);

            for (int i = 0; i < words.Count; i++)
            {
                if (words[i] == null)
                {
                    result.Add("\r\n");
                    words.RemoveAt(i);
                }

                if (Array.BinarySearch<long>(Numbers.PurePrimes, Convert.ToInt64(i + 1)) != -1)
                {
                    result.Add(words[i].ToString(agent.Client.ActiveTextMode) + " ");
                }
            }

            return result;
        }

        public static List<string> DoJumpWordsByFibonacciNumbers(ResearchAgent agent, VerseCollection verses)
        {
            List<string> result = new List<string>();

            List<Word> words = new List<Word>();
            foreach (Verse verse in verses)
            {
                words.AddRange(verse.Words);
                words.Add(null); // to mark end of verse
            }
            words.RemoveAt(words.Count - 1);

            for (int i = 0; i < words.Count; i++)
            {
                if (words[i] == null)
                {
                    result.Add("\r\n");
                    words.RemoveAt(i);
                }

                if (Numbers.Fibonaccis.Contains(i + 1))
                    result.Add(words[i].ToString(agent.Client.ActiveTextMode) + " ");                
            }

            return result;
        }

        public static List<string> DoJumpWordsByPiDigits(ResearchAgent agent, VerseCollection verses)
        {
            List<string> result = new List<string>();

            List<Word> words = new List<Word>();
            foreach (Verse verse in verses)
            {
                words.AddRange(verse.Words);
                words.Add(null); // to mark end of verse
            }
            words.RemoveAt(words.Count - 1);

            for (int i = 0; i < words.Count; i++)
            {
                if (words[i] == null)
                {
                    result.Add("\r\n");
                    words.RemoveAt(i);
                }


                if (Array.IndexOf(Numbers.PiDigits, i + 1) != -1)
                {
                    result.Add(words[i].ToString(agent.Client.ActiveTextMode) + " ");
                }
            }

            return result;
        }

        public static List<string> DoJumpWordsByEulerDigits(ResearchAgent agent, VerseCollection verses)
        {
            List<string> result = new List<string>();
            //TODO: Do Jump by Euler Digits
            return result;
        }

        public static List<string> DoJumpWordsByGoldenRatioDigits(ResearchAgent agent, VerseCollection verses)
        {
            List<string> result = new List<string>();
            //TOOD: Do Jump by Golden Ratio Digits
            return result;
        }
        #endregion
    }
}